#include "RawImage.h"
#include "NativeImage.h"

using namespace WONAPI;

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void RawImage::Draw(DisplayContext *theContext, int x, int y, int left, int top, int width, int height)
{
	NativeImagePtr aNativeImage = GetNative(theContext);
	aNativeImage->Draw(theContext,x,y,left,top,width,height);
}





///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
RawImage32::RawImage32(int theWidth, int theHeight) : RawImage(RawImageType_32)
{
	mWidth = theWidth;
	mHeight = theHeight;
	mDoTransparency = false;
	mImageData = new DWORD[theWidth*theHeight];

	mImageEnd = mImageData + theWidth*theHeight;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
RawImage32::~RawImage32()
{
	delete [] mImageData;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
ImagePtr RawImage32::Duplicate()
{
	RawImage32Ptr anImage = PlatformDuplicate(); //new RawImage32(mWidth,mHeight);
	anImage->CopyInfo(this);
	memcpy(anImage->mImageData,mImageData,mWidth*mHeight*4);
	return anImage.get();
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void RawImage32::SetPixel(int x, int y, DWORD theColor)
{
	*(mImageData + y*mWidth + x) = theColor;
}
	
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
DWORD RawImage32::GetPixel(int x, int y)
{
	return *(mImageData + y*mWidth + x);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
DWORD* RawImage32::StartRowTraversal(int theRow)
{
	mRowPtr = mImageData + theRow*mWidth;
	mRowEnd = mRowPtr + mWidth;
	return mRowPtr;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
NativeImagePtr RawImage32::GetNative(DisplayContext *theContext)
{
	if(mDoTransparency)
	{
		int aWidth = GetWidth(), aHeight = GetHeight();
		RawImage1Ptr aMask = theContext->CreateRawImage1(aWidth,aHeight); //new RawImage1(aWidth,aHeight);
		for(int y=0; y<aHeight; y++)
		{
			aMask->StartRowTraversal(y);
			StartRowTraversal(y);
			while(HasMoreRowPixels())
			{
				if((GetRowPixel()&0xff000000)==0)
				{
					SetRowPixel(0);
					aMask->SetRowPixel(true);
				}
				else
					aMask->SetRowPixel(false);

				NextRowPixel();
				aMask->NextRowPixel();
			}
		}

		NativeImagePtr aNativeImage = PlatformGetNative(theContext);
		aNativeImage->SetTransparentMask(aMask->GetMask(theContext));
		return aNativeImage;
	}
	else
		return PlatformGetNative(theContext);
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
RawImage8::RawImage8(int theWidth, int theHeight, Palette *thePalette) : RawImage(RawImageType_8)
{
	mWidth = theWidth;
	mHeight = theHeight;
	mPalette = thePalette;
	mTransparentColor = -1;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void RawImage8::FinishConstructor()
{
	mRowPad = mBytesPerRow - mWidth;
	mImageData = new unsigned char[mHeight*mBytesPerRow];
	mImageEnd = mImageData + mBytesPerRow*mHeight;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
RawImage8::~RawImage8()
{
	delete mImageData;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
ImagePtr RawImage8::Duplicate()
{
	RawImage8Ptr anImage = PlatformDuplicate(); //new RawImage8(mWidth,mHeight,mPalette);
	anImage->CopyInfo(this);
	memcpy(anImage->mImageData,mImageData,mBytesPerRow*mHeight);
	return anImage.get();
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void RawImage8::SetPixel(int x, int y, unsigned char theColor)
{
	*(mImageData + y*mBytesPerRow + x) = theColor;
}
	
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
unsigned char RawImage8::GetPixel(int x, int y)
{
	return *(mImageData + y*mBytesPerRow + x);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
unsigned char* RawImage8::StartRowTraversal(int theRow)
{
	mRowPtr = mImageData + theRow*mBytesPerRow;
	mRowEnd = mRowPtr + mWidth;
	return mRowPtr;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
NativeImagePtr RawImage8::GetNative(DisplayContext *theContext)
{
	NativeImagePtr aNativeImage = PlatformGetNative(theContext);

	if(mTransparentColor!=-1)
	{
		RawImage1Ptr aMask = theContext->CreateRawImage1(mWidth,mHeight); //new RawImage1(mWidth,mHeight);

		for(int y=0; y<mHeight; y++)
		{
			StartRowTraversal(y);
			aMask->StartRowTraversal(y);
			while(HasMoreRowPixels())
			{
				aMask->SetRowPixel(GetRowPixel()==mTransparentColor);
				aMask->NextRowPixel();
				NextRowPixel();
			}
		}

		aNativeImage->SetTransparentMask(aMask->GetMask(theContext));
	}

	return aNativeImage;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
RawImage32Ptr RawImage8::GetRawImage32()
{
	RawImage32Ptr anImage = Window::CreateRawImage32(mWidth,mHeight);
	if(HasTransparency())
		anImage->SetDoTransparency(true);

	anImage->StartRowTraversal(0);
	StartRowTraversal(0);

	while(HasMoreRows())
	{
		while(HasMoreRowPixels())
		{
			unsigned char anIndex = GetRowPixel();
			DWORD aColor = mPalette->GetColor(anIndex);
			if(anIndex!=mTransparentColor)
				aColor |= 0xff000000;
			else
				aColor &= ~0xff00000;

			anImage->SetRowPixel(aColor);

			anImage->NextRowPixel();
			NextRowPixel();
		}
		NextRow();
		anImage->NextRow();
	}

	return anImage;
}



///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
RawImage1::RawImage1(int theWidth, int theHeight) : RawImage(RawImageType_1)
{
	mWidth = theWidth;
	mHeight = theHeight;
	mBytesPerRowMinusPad = mWidth/8;
	mCompleteBytesPerRow = mBytesPerRowMinusPad;
	mWidthMod8 = mWidth%8;
	if(mWidthMod8!=0)
		mBytesPerRowMinusPad++;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void RawImage1::FinishConstructor()
{
	mRowPad = mBytesPerRow - mBytesPerRowMinusPad;
	if(mWidthMod8!=0)
		mRowPad++;

	mEndRowMask = 1<<(8-mWidthMod8);

	mImageData = new unsigned char[mBytesPerRow*mHeight];
	mImageEnd = mImageData + mBytesPerRow*mHeight;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
RawImage1::~RawImage1()
{
	delete mImageData;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void RawImage1::SetPixel(int x, int y, bool on)
{
	int aMask = (1<<(7-((x>>3)&0x7))); // 1<<(7-(x%8))
	if(on)
		*(mImageData + y*mBytesPerRow + x/8) |= aMask;
	else
		*(mImageData + y*mBytesPerRow + x/8) &= ~aMask;
}
	
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool RawImage1::GetPixel(int x, int y)
{
	int aMask = (1<<(7-((x>>3)&0x7))); // 1<<(7-(x%8))
	return (*(mImageData + y*mBytesPerRow + x/8) & aMask)?true:false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
unsigned char* RawImage1::StartRowTraversal(int theRow)
{
	mRowMask = 128;
	mRowPtr = mImageData + theRow*mBytesPerRow;
	mRowEnd = mRowPtr + mCompleteBytesPerRow;
//	if(mWidthMod8==0)
//		mRowEnd--;

	return mRowPtr;
}

